#include "utility.h"

char* getinputstring()
{
	int size = BUFF_SIZE;
	char *strbuffer = (char*)malloc(sizeof(char)*size);

	char c;
	int i = 0;
	for(; (c = getchar()) != '\n'; i++)
	{
	 	if(i >= size-1)                                          //Allocate some
		{
			size += BUFF_SIZE;
			strbuffer = realloc(strbuffer, (size+=BUFF_SIZE));
		}
		*(strbuffer+i) = c;
	}
	*(strbuffer+i) = '\0';
	return strbuffer;
}

void sanatize(char* cmd)
{
	char* newString = malloc( sizeof(char) * (strlen(cmd)+1) );

	int start = 0;
	int end = strlen(cmd) + 1;

	for(int i = 0; i < end; i++)
	{
		if(cmd[i] == ' ' && i == start)
		{
			start++;
		}
		if(cmd[i] == '#')
		{
			end = (cmd[i-1] == ' ')?i-1:i;
			break;
		}
	}
	strncpy(newString,(cmd+start), end-start);
	strcpy(cmd, newString);
	cmd[end-start] = '\0';
	free(newString);
}


char** getPathEnv()
{
	char* envPath = getenv("PATH");

	char* tmp = malloc(sizeof(char)* (strlen(envPath)+1));
	strcpy(tmp, envPath);
	return getTokens(tmp, ":");
}

int countchar(const char *str, const char* c)
{
	int count = 0;
	int size = strlen(str);

	for(int i = 0; i < size; i++)
	{
		if(str[i] == c[0])
			count++;
	}
	return count;
}

char** getTokens(const char *str, const char* sep)
{
	int nTokens = countchar(str, sep);

	int retSize = sizeof(char*) * (nTokens +2 );
	char **ret = malloc(retSize);

	char *savePTR;

	char *arg1 = str;
	for(int i = 0; ; arg1 = NULL, i++)
	{
		char *dir = strtok_r(arg1, sep, &savePTR);
		if(dir == NULL)
		{
			ret[i] = NULL;
			break;
		}

		int size = strlen(dir) +1;
		ret[i] = malloc(sizeof(char) * size );
		strcpy(ret[i], dir);
	}

	ret[nTokens+1] = NULL;

	return ret;
}

char** expandFileName(const char *path, const char* match)
{
	char **ret;

	ftwMatch.fileNames = malloc(sizeof(char*) * BUFF_SIZE);
	ftwMatch.size = 0;
	ftwMatch.capacity = BUFF_SIZE;

	if(unescapedRegex(match) == 0)
	{
		ret = malloc(sizeof(char*) *2);
		int cpySize = strlen(match) + 1;
		ret[0] = malloc(sizeof(char) * cpySize);
		strcpy(ret[0], match);
		ret[0][cpySize] = '\0';
		ret[1] = NULL;
		return ret;
	}

	if(match[0] == '/')
	{
		treeTraversal("/", (match+1));
	}
	else if(match[0] == '.')
	{
		if(match[1] == '.')
		{
			char *newPath = malloc(strlen(path));
			int copying = 0;
			for(int i = strlen(path); i >= 0; i--)
			{
				if(path[i] == '/' && copying == 0)
				{
					copying = 1;
					newPath[i] = '\0';
				}
				else
					newPath[i] = path[i];
			}
			treeTraversal(newPath, (match+3));
		}
		else if(match[1] == '/')
			treeTraversal(path, (match+2));
		else
			treeTraversal(path, match);
	}
	else
		treeTraversal(path, match);

	ret = ftwMatch.fileNames;

	sortFileNames(ret);

	ftwMatch.fileNames = NULL;
	ftwMatch.size = 0;
	ftwMatch.capacity = 0;

	return ret;

}

void treeTraversal(const char *path, const char *patern)
{
	int size = strlen(patern) + 1;
	char *searchPt = malloc(sizeof(char) * size);
	int endPatern = 0;

	unsigned int i;
	for(i = 0; patern[i] != '\0' &&  patern[i] != '/'; i++)
		searchPt[i] = patern[i];
	searchPt[i] = '\0';

	if(i >= strlen(patern))
		endPatern = 1;

	char *fileRegex = formRegex(searchPt);

	free(searchPt);

	regex_t regExp;

	if(regcomp(&regExp, fileRegex, REG_EXTENDED) != 0)
	{
		printf("Could not create regex engine.\n");
		return;
	}

	free(fileRegex);

	DIR *dirp;
	struct dirent *dp;

	if( (dirp = opendir(path)) == NULL)
	{
		perror("Couldn't open dir");
		return;
	}

	while((dp = readdir(dirp)) != NULL)
	{
		if(regexec(&regExp, dp->d_name, 0, NULL, 0) == 0)
		{
			if(endPatern)
			{
				if( ftwMatch.size >= ftwMatch.capacity )
				{
					ftwMatch.capacity *= 2;
					ftwMatch.fileNames = realloc(ftwMatch.fileNames, ftwMatch.capacity);
				}
				int fNameSize = strlen(path) + strlen(dp->d_name) + 2;
				ftwMatch.fileNames[ftwMatch.size] = malloc( sizeof(char) *  fNameSize);
				strcpy(ftwMatch.fileNames[ftwMatch.size], path);
				strcat(ftwMatch.fileNames[ftwMatch.size], "/");
				strcat(ftwMatch.fileNames[ftwMatch.size], dp->d_name);
				ftwMatch.fileNames[fNameSize] = '\0';

				if(isDir(ftwMatch.fileNames[ftwMatch.size]) == 1)
				{
					free(ftwMatch.fileNames[ftwMatch.size]);
					continue;
				}

				ftwMatch.size++;
				ftwMatch.fileNames[ftwMatch.size] = NULL;
			}
			else
			{
				int newPathSize = strlen(path) + strlen(dp->d_name) + 2;
				char *newPath = malloc(newPathSize);
				strcpy(newPath, path);
				if(newPath[strlen(path)-1] != '/')
					strcat(newPath, "/");
				strcat(newPath, dp->d_name);

				if(isDir(newPath) && (dp->d_name[0] != '.' && (dp->d_name[1] != '\0' || dp->d_name[1] != '.')))
					treeTraversal(newPath, (patern+i+1));

				free(newPath);
			}
		}
	}
	regfree(&regExp);
}

char* formRegex(const char *str)
{
	int size = strlen(str);
	int buff_size = size+10;
	char *regex_str = malloc(buff_size);

	int escaped = 0;
	int j = 0;
	for(int i = 0; i < size; i++, j++)
	{
		if( (str[i] == '*' || str[i] == '?' || str[i] == '.') &&  escaped == 0 )
		{
			if(j >= (buff_size-1))
				regex_str = realloc(regex_str, (buff_size*=2));
			regex_str[j] = (str[i] == '.')? '\\' : '.';
			j++;
		}
		if(str[i] == '\\')
			escaped = 1;
		else
			escaped = 0;

		if(str[i] == '?')
		{
			j--;
			continue;
		}
		regex_str[j] = str[i];
	}
	regex_str[j] = '\0';
	return regex_str;
}

char* getExecPath(char **envPath, const char* name)
{
	int i = 0;
	struct stat sb;
	int nameSize = strlen(name) + 1;
	int buffSize = BUFF_SIZE;
	char* fullName = malloc(buffSize);

	while(envPath[i] != NULL)
	{
		if( (int)(strlen(envPath[i]) + nameSize) >= (buffSize -1) )
		{
			buffSize = nameSize + strlen(envPath[i]);
			fullName = realloc(fullName, buffSize);
		}

		strcpy(fullName, envPath[i]);
		strcat(fullName, "/");
		strcat(fullName, name);

		if(stat(fullName, &sb) == 0)
		{
			if( ((sb.st_mode & S_IXUSR) && sb.st_uid == getuid()) ||
				((sb.st_mode & S_IXGRP) && sb.st_gid == getgid()) ||
				(sb.st_mode & S_IXOTH) )
				return fullName;
		}
		i++;
	}

	free(fullName);

	return NULL;
}

int isDir(const char* str)
{
	struct stat sb;

	if(stat(str, &sb) != 0)
		return 0;

	if(S_ISDIR(sb.st_mode))
		return 1;
	else
		return 0;
}

int unescapedRegex(const char* str)
{
	for(int i = 0; str[i] != '\0'; i++)
		if(str[i] == '*' || str[i] == '?')
			if(i == 0 || str[i-1] != '\\')
				return 1;
	return 0;
}

char** parseArgs(const char *str)
{
	int pos1 = 0;
	int pos2 = 0;
	int par = 0;	//BIT 0 = ', BIT 1 = "

	int nArgs = 0;
	int argCap = 5;
	char** ret = malloc(argCap * sizeof(char*));


	for(int i = 0; str[i] != '\0'; i++)
	{
		if(pos1 < pos2)
		{
			if((str[i] == '\'' || str[i] == '\"') && (i>0 && str[i-1] != '\\') && par == 0)
			{
				par = 0 | ((str[i] == '\'')?1:2);
				pos1 = i+1;
				i++;
			}
			else if( (str[i] != '\\' && str[i] != ' ') && (i > 0 || str[i-1] == ' ') && par == 0)
				pos1 = i;
		}
		if(pos1 >= pos2)
		{
			if((str[i] == '\'' || str[i] == '\"') && ( str[i-1] != '\\' ))
			{
				if( (par & ((str[i] == '\'')?1:2)) != 0 )
				{
					pos2 = i;
					par = 0;
				}
			}
			else if((str[i] != '\\' && str[i] != ' ') && (str[i+1] == '\0' || str[i+1] == ' ') && par == 0)
			{
				pos2 = i+1;
			}

			if(pos2 > pos1)
			{
				if(nArgs >= argCap -1)
				{
					argCap *= 2;
					ret = realloc(ret, argCap);
				}
				int buffSize = 1 + (pos2 - pos1);
				buffSize *= sizeof(char);
				ret[nArgs] = malloc(buffSize);
				strncpy(ret[nArgs], (str+pos1), pos2-pos1);
				ret[nArgs][buffSize-1] = '\0';
				nArgs++;
			}
		}
	}
	ret[nArgs] = NULL;
	for(int i = 0; i < nArgs; i++)
		removeUnescaped(&ret[i]);
	return ret;
}

void removeUnescaped(char** str)
{
	int len = strlen(*str);
	char* newstr = malloc(sizeof(char) * (len + 1));
	int index = 0;

	for(int i = 0; i < len; i++)
	{
		if((*str)[i] == '\\' && ((*str)[i+1] == ' ' || (*str)[i+1] == '\\') )
				continue;

		newstr[index] = (*str)[i];
		index++;
	}
	newstr[index] = '\0';
	free(*str);
	*str = newstr;
}

void freeArr(char** arr)
{
	for(int i = 0; arr[i] != NULL; i++)
	{
		free(arr[i]);
	}
	free(arr);
}

void sortFileNames(char** names)
{
	int changes;
	do
	{
		changes = 0;
		for(int i = 0; names[i] != NULL && names[i+1] != NULL; i++)
		{
			int cmp = strcmp(names[i], names[i+1]);
			if(cmp > 0)
			{
				char *tmp = names[i];
				names[i] = names[i+1];
				names[i+1] = tmp;
				changes = 1;
			}
		}
	}while(changes == 1);
}












